package com.aabte.springcloudlearn.ribbonhystrixcustomerdemo.service;

import com.aabte.springcloudlearn.ribbonhystrixcustomerdemo.hystrix.CacheCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

/**
 * @author Daniel
 */
@Slf4j
@Service
public class CacheCustomerService {

    @Autowired
    private RestTemplate restTemplate;

    // ========== Start 使用继承的方式 ==========

    public void openCacheByExtends(String cacheKey) {
        log.info("Start openCacheByExtends. cacheKey: {}", cacheKey);

        CacheCommand cacheCommand1 = new CacheCommand(com.netflix.hystrix.HystrixCommand.Setter.withGroupKey(
                HystrixCommandGroupKey.Factory.asKey(CacheCommand.COMMAND_GROUP)
        ).andCommandKey(
                HystrixCommandKey.Factory.asKey(CacheCommand.COMMAND_KEY)
        ), restTemplate, cacheKey);

        CacheCommand cacheCommand2 = new CacheCommand(com.netflix.hystrix.HystrixCommand.Setter.withGroupKey(
                HystrixCommandGroupKey.Factory.asKey(CacheCommand.COMMAND_GROUP)
        ).andCommandKey(
                HystrixCommandKey.Factory.asKey(CacheCommand.COMMAND_KEY)
        ), restTemplate, cacheKey);

        Integer result1 = cacheCommand1.execute();
        Integer result2 = cacheCommand2.execute();

        log.info("first request result: {}, and secend request result: {}", result1, result2);

    }

    public void clearCacheByExtends(String cacheKey) {
        CacheCommand.flushRequestCache(cacheKey);
        log.info("请求缓存已清空！ cacheKey: {}", cacheKey);
    }

    // ========== End 使用继承的方式 ==========



    // ========== Start 使用注解的方式一：使用方法生成缓存Key ==========

    /**
     * 此方法的结果会被缓存
     */
    @CacheResult(cacheKeyMethod = "getCacheKey")
    @HystrixCommand(commandKey = "openCacheByAnnotation1")
    public Integer openCacheByAnnotation1(String cacheKey) {
        log.info("Start openCacheByAnnotation1. cacheKey: {}", cacheKey);
        Integer result = restTemplate.getForObject("http://hello-service/hystrix/cache", Integer.class);
        log.info("End openCacheByAnnotation1. result: {}", result);
        return result;
    }

    /**
     * {@link CacheRemove}注解建议直接用在更新方法上
     */
    @CacheRemove(
            commandKey = "openCacheByAnnotation1",
            cacheKeyMethod = "getCacheKey")
    @HystrixCommand
    public void flushCacheByAnnotation1(String cacheKey) {
        log.info("Invoke flushCacheByAnnotation1. cacheKey: {}", cacheKey);
    }

    /**
     * 使用这个方法生成cacheKey
     * 注意：
     * 1、这个方法的入参的类型必须与缓存方法的入参类型相同，如果不同被调用会报这个方法找不到的异常
     * 2、这个方法的返回值一定是String类型
     */
    public String getCacheKey(String cacheKey) {
        return cacheKey;
    }

    // ========== End 使用注解的方式一 ==========



    // ========== Start 使用注解的方式二：指定参数作为缓存Key ==========

    @CacheResult
    @HystrixCommand(commandKey = "openCacheByAnnotation2")
    public Integer openCacheByAnnotation2(@CacheKey String cacheKey) {
        log.info("Start openCacheByAnnotation2. cacheKey: {}", cacheKey);
        Integer result = restTemplate.getForObject("http://hello-service/hystrix/cache", Integer.class);
        log.info("End openCacheByAnnotation2. result: {}", result);
        return result;
    }

    @CacheRemove(commandKey = "openCacheByAnnotation2")
    @HystrixCommand
    public void flushCacheByAnnotation2(@CacheKey String cacheKey){
        log.info("Invoke flushCacheByAnnotation2. cacheKey: {}", cacheKey);
    }

    // ========== End 使用注解的方式二 ==========



    // ========== Start 使用注解的方式三：默认使用所有参数作为缓存Key ==========

    @CacheResult
    @HystrixCommand(commandKey = "openCacheByAnnotation3")
    public Integer openCacheByAnnotation3(String cacheKey) {
        log.info("Start openCacheByAnnotation3. cacheKey: {}", cacheKey);
        Integer result = restTemplate.getForObject("http://hello-service/hystrix/cache", Integer.class);
        log.info("End openCacheByAnnotation3. result: {}", result);
        return result;
    }

    @CacheRemove(commandKey = "openCacheByAnnotation3")
    @HystrixCommand
    public void flushCacheByAnnotation3(String cacheKey){
        log.info("Invoke flushCacheByAnnotation3. cacheKey: {}", cacheKey);
    }

    // ========== End 使用注解的方式三 ==========


}
